package me.zhengjie.tools.service.impl

import cn.hutool.core.util.ObjectUtil
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Root
import jakarta.servlet.http.HttpServletResponse
import me.zhengjie.common.config.FileProperties
import me.zhengjie.common.exception.BadRequestException
import me.zhengjie.common.utils.*
import me.zhengjie.common.utils.FileUtil.checkSize
import me.zhengjie.common.utils.FileUtil.downloadExcel
import me.zhengjie.common.utils.FileUtil.getExtensionName
import me.zhengjie.common.utils.FileUtil.getFileNameNoEx
import me.zhengjie.common.utils.FileUtil.getFileType
import me.zhengjie.common.utils.FileUtil.upload
import me.zhengjie.tools.domain.LocalStorage
import me.zhengjie.tools.repository.LocalStorageRepository
import me.zhengjie.tools.service.LocalStorageService
import me.zhengjie.tools.service.dto.LocalStorageDTO
import me.zhengjie.tools.service.dto.LocalStorageQueryCriteria
import me.zhengjie.tools.service.mapper.LocalStorageMapper
import org.springframework.cache.annotation.CacheConfig
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.io.File
import java.io.IOException

/**
 * @author Kuki Wu
 * @date 2019-09-05
 */
@Service
@CacheConfig(cacheNames = ["localStorage"])
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = [Exception::class])
class LocalStorageServiceImpl (
    private val localStorageRepository: LocalStorageRepository,
    private val localStorageMapper: LocalStorageMapper,
    private val properties: FileProperties
) : LocalStorageService {
//    @Value("\${file.path}")
//    private val path: String? = null
//
//    @Value("\${file.maxSize}")
//    private val maxSize: Long = 0

    @Override
    override fun queryAll(criteria: LocalStorageQueryCriteria?, pageable: Pageable?): PageResult<LocalStorageDTO?>? {
        val page = localStorageRepository.findAll(
            { root, criteriaQuery, criteriaBuilder -> QueryHelp.getPredicate(root, criteria, criteriaBuilder) },
            pageable!!
        )
        return PageUtil.toPage(page.map(localStorageMapper::toDto))
    }
//    @Cacheable
//    override fun queryAll(criteria: LocalStorageQueryCriteria, pageable: Pageable?): Any? {
//        val page =
//            localStorageRepository.findAll(Specification { root: Root<LocalStorage>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
//                QueryHelp.getPredicate(
//                    root,
//                    criteria,
//                    criteriaBuilder
//                )
//            }, pageable!!)
//        return PageUtil.toPage(page.map { entity: LocalStorage? -> localStorageMapper.toDto(entity) })
//    }

    @Cacheable
    override fun queryAll(criteria: LocalStorageQueryCriteria): List<LocalStorageDTO?>? {
        return localStorageMapper.toDto(localStorageRepository.findAll { root: Root<LocalStorage?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
            QueryHelp.getPredicate(
                root,
                criteria,
                criteriaBuilder
            )
        })
    }

    @Cacheable(key = "#p0")
    override fun findById(id: Long): LocalStorageDTO? {
        val localStorage = localStorageRepository.findById(id).orElseGet { LocalStorage() }!!
        ValidationUtil.isNull(localStorage.id, "LocalStorage", "id", id)
        return localStorageMapper.toDto(localStorage)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun create(name: String?, multipartFile: MultipartFile): LocalStorageDTO? {
        checkSize(properties.maxSize!!, multipartFile.size)
        val suffix = getExtensionName(multipartFile.originalFilename)
        val type = getFileType(suffix)
        //val file = upload(multipartFile, path + type + File.separator)
        val file = upload(multipartFile, properties.getPath()!!.path!!)

        if (ObjectUtil.isNull(file)) {
            throw BadRequestException("上传失败")
        }
        return try {
            var name = if (org.apache.commons.lang3.StringUtils.isBlank(name!!)) getFileNameNoEx(multipartFile.originalFilename) else name
            val localStorage = LocalStorage(
                file!!.name,
                name,
                suffix,
                file.path,
                type,
                me.zhengjie.common.utils.FileUtil.getSize(multipartFile.size),
                me.zhengjie.common.utils.SecurityUtils.username
            )
            localStorageMapper.toDto(localStorageRepository.save(localStorage))
        } catch (e: Exception) {
            cn.hutool.core.io.FileUtil.del(file)
            throw e
        }
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun update(resources: LocalStorage) {
        val localStorage = localStorageRepository.findById(resources.id!!).orElseGet { LocalStorage() }!!
        ValidationUtil.isNull(localStorage.id, "LocalStorage", "id", resources.id!!)
        localStorage.copy(resources)
        localStorageRepository.save(localStorage)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun delete(id: Long) {
        val storage = localStorageRepository.findById(id).orElseGet { LocalStorage() }!!
        cn.hutool.core.io.FileUtil.del(storage.path)
        localStorageRepository.delete(storage)
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun deleteAll(ids: Array<Long>) {
        for (id in ids) {
            val storage = localStorageRepository.findById(id).orElseGet { LocalStorage() }!!
            cn.hutool.core.io.FileUtil.del(storage.path)
            localStorageRepository.delete(storage)
        }
    }

    @Throws(IOException::class)
    override fun download(queryAll: List<LocalStorageDTO?>?, response: HttpServletResponse?) {
        val list: MutableList<Map<String?, Any?>?> = ArrayList()
        for (localStorageDTO in queryAll!!) {
            val map: MutableMap<String?, Any?> = LinkedHashMap()
            map["文件名"] = localStorageDTO!!.realName
            map["备注名"] = localStorageDTO.name
            map["文件类型"] = localStorageDTO.type
            map["文件大小"] = localStorageDTO.size
            map["操作人"] = localStorageDTO.operate
            map["创建日期"] = localStorageDTO.createTime
            list.add(map)
        }
        downloadExcel(list, response!!)
    }
}